package main

// 多线程下载

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"sync"

	"C"

	"github.com/asmcos/requests"
)

type Man_hua_data struct {
	SectionName  string   `json:"sectionName"`  // 章节名
	SectionUrl   string   `json:"sectionUrl"`   //章节url
	ImgPage      int      `json:"imgPage"`      //页数
	PicturesUrls []string `json:"picturesUrls"` //照片url
}

//export C_Down_work_of_thread
func C_Down_work_of_thread(work_name_path, sava_dir *C.char, threed_num int) {
	Down_work_of_thread(C.GoString(work_name_path), C.GoString(sava_dir), threed_num)
}

func Down_work_of_thread(work_name_path string, sava_dir string, threed_num int) {
	// 根据work_name读取json数据
	json_data, e := os.ReadFile(work_name_path)
	if e != nil {
		fmt.Println("没有" + work_name_path + "文件")
		fmt.Println(e)
		return
	}

	// work_name := GetFileName(work_name_path)

	// json数据转为go对象数据
	var work_data []Man_hua_data
	json.Unmarshal(json_data, &work_data)

	// 下载数据分组

	// 定义等待组，用于等待所有 Goroutine 完成
	var wg sync.WaitGroup

	// 计算每个子切片的长度
	totalLength := len(work_data)
	if totalLength <= threed_num {
		for i, sections := range work_data{
			wg.Add(1) /// 增加等待组的计数
			go down_img(i, &wg, []Man_hua_data{sections}, sava_dir)
		}
		wg.Wait()
		return
	}
	subSliceLength := totalLength / threed_num

	// 用循环分割数组并创建threed_num个子切片
	var work_sub_slices [][]Man_hua_data
	for i := 0; i < threed_num; i++ {
		start := i * subSliceLength
		end := (i + 1) * subSliceLength

		// 使用切片操作创建子切片
		work_sub_slices = append(work_sub_slices, work_data[start:end])
	}

	// 根据数组数量开启相应数量的 Goroutine
	for i, sections := range work_sub_slices {
		wg.Add(1) /// 增加等待组的计数

		go down_img(i, &wg, sections, sava_dir)
	}

	// 等待所有 Goroutine 完成
	defer wg.Wait()

}

// 下载照片
func down_img(id int, wg *sync.WaitGroup, sections []Man_hua_data, sava_dir string) {
	defer wg.Done() /// 在 Goroutine 完成时减少等待组的计数

	// 设置请求头
	header := requests.Header{}
	header["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0"

	//设置超时时间
	requests.Requests().SetTimeout(15)

	// 获取要下载的长度
	imgs_len := 0
	for _, section := range sections {
		imgs_len += len(section.PicturesUrls)
	}
	// 已经下载的长度
	imgs_len_ed := 0

	// 开始下载照片
	for _, section := range sections {
		section_name := section.SectionName
		section_name = filterIllegalCharacters(section_name)
		section_path := sava_dir + "/" + section_name
		// 使用os.MkdirAll创建文件夹，如果文件夹已存在则不会报错
		err := os.MkdirAll(section_path, os.ModePerm)

		if err != nil {
			fmt.Println("无法创建文件夹:", err)
			break
		}
		n := 0 // 图片序号
		pictureUrls := section.PicturesUrls
		var file_name string
		for _, imgurls := range pictureUrls {
			if n < 10 {
				file_name = section_path + "/" + strconv.Itoa(section.ImgPage) + "_00" + strconv.Itoa(n) + ".jpg"
			} else if n < 100 {
				file_name = section_path + "/" + strconv.Itoa(section.ImgPage) + "_0" + strconv.Itoa(n) + ".jpg"
			} else {
				file_name = section_path + "/" + strconv.Itoa(section.ImgPage) + "_" + strconv.Itoa(n) + ".jpg"
			}

			if !fileExists(file_name) {
				req, err := requests.Get(imgurls, header)
				if err != nil {
					fmt.Println(err)
					imgs_len -= 1
					break
				}
				if req.R.Status == "200 OK" {
					err = os.WriteFile(file_name, req.Content(), 0666)
					if err != nil {
						fmt.Println(err)
						imgs_len -= 1
						break
					}
					imgs_len_ed += 1
					fmt.Printf("线程%d:%s下载完成,进度%d/%d\n", id, file_name, imgs_len_ed, imgs_len)
				} else {
					err := os.Remove(file_name)
					if err != nil {
						fmt.Printf("%s无法删除\n", file_name)
						fmt.Println(err)
					} else {
						fmt.Printf("线程%d:%s文件下载失败,删除成功,进度%d/%d\n\n", id, file_name, imgs_len_ed, imgs_len)
					}
					imgs_len -= 1
				}
			} else {
				imgs_len -= 1
			}
			n += 1
		}
	}
}

// 过滤非法字符
func filterIllegalCharacters(input string) string {
	// 定义一个正则表达式，匹配合法字符，这里只允许字母、数字和空格
	regex := regexp.MustCompile(`[\\/:.*?"<>|]`)

	// 使用正则表达式替换非法字符为空字符串
	filtered := regex.ReplaceAllString(input, "")

	return filtered
}

// 判断文件是否存在
func fileExists(filePath string) bool {
	_, err := os.Stat(filePath)
	if err == nil {
		return true // 文件存在
	}
	if os.IsNotExist(err) {
		return false // 文件不存在
	}
	return false // 出现错误，无法确定文件是否存在
}

// 获取文件名
func GetFileName(filePath string) string {
	// 使用filepath.Base()函数获取文件名
	fileName := filepath.Base(filePath)
	fileName = strings.Split(fileName, ".")[0]
	return fileName
}
